using UniversalAdmin.Application.DTOs;
using UniversalAdmin.Domain.Entities;
using UniversalAdmin.Domain.Repositories;
using UniversalAdmin.Shared.Enums;

namespace UniversalAdmin.Application.Services;

public class MenuService : IMenuService
{
    private readonly IMenuRepository _menuRepository;
    private readonly IMenuRoleRepository _menuRoleRepository;

    public MenuService(IMenuRepository menuRepository, IMenuRoleRepository menuRoleRepository)
    {
        _menuRepository = menuRepository;
        _menuRoleRepository = menuRoleRepository;
    }

    public async Task<IEnumerable<MenuDto>> GetAllMenusAsync()
    {
        var menus = await _menuRepository.GetAllAsync();
        return menus.Select(MapToDto);
    }

    public async Task<IEnumerable<MenuDto>> GetMenuTreeAsync()
    {
        var allMenus = await _menuRepository.GetAllAsync();
        var menuDtos = allMenus.Select(MapToDto).ToList();
        
        // 构建树形结构
        var rootMenus = menuDtos.Where(m => m.ParentId == null).OrderBy(m => m.SortOrder).ToList();
        foreach (var rootMenu in rootMenus)
        {
            BuildMenuTree(rootMenu, menuDtos);
        }
        
        return rootMenus;
    }

    // 根据ID获取单个菜单
    public async Task<MenuDto?> GetMenuByIdAsync(Guid id)
    {
        // 调用仓储层根据ID获取菜单
        var menu = await _menuRepository.GetByIdAsync(id);
        // 如果菜单存在，映射为DTO并返回；否则返回null
        return menu != null ? MapToDto(menu) : null;
    }

    // 创建新菜单
    public async Task<MenuDto> CreateMenuAsync(CreateMenuDto dto)
    {
        // 根据DTO创建菜单实体
        var menu = new Menu
        {
            Name = dto.Name,
            Path = dto.Path,
            Icon = dto.Icon,
            ParentId = dto.ParentId,
            SortOrder = dto.SortOrder,
            CreatedAt = DateTime.UtcNow
        };

        // 调用仓储层添加菜单
        var createdMenu = await _menuRepository.AddAsync(menu);
        // 将新创建的菜单映射为DTO并返回
        return MapToDto(createdMenu);
    }

    // 更新菜单
    public async Task<MenuDto?> UpdateMenuAsync(Guid id, UpdateMenuDto dto)
    {
        // 调用仓储层根据ID获取菜单
        var menu = await _menuRepository.GetByIdAsync(id);
        // 如果菜单不存在，返回null
        if (menu == null) return null;

        // 更新菜单属性
        menu.Name = dto.Name;
        menu.Path = dto.Path;
        menu.Icon = dto.Icon;
        menu.ParentId = dto.ParentId;
        menu.SortOrder = dto.SortOrder;
        menu.UpdatedAt = DateTime.UtcNow;

        // 调用仓储层更新菜单
        await _menuRepository.UpdateAsync(menu);
        // 将更新后的菜单映射为DTO并返回
        return MapToDto(menu);
    }

    // 删除菜单
    public async Task<bool> DeleteMenuAsync(Guid id)
    {
        // 调用仓储层根据ID获取菜单
        var menu = await _menuRepository.GetByIdAsync(id);
        // 如果菜单不存在，返回false
        if (menu == null) return false;

        // 检查是否有子菜单
        var hasChildren = await _menuRepository.HasChildrenAsync(id);
        if (hasChildren)
        {
            throw new InvalidOperationException("无法删除有子菜单的菜单项");
        }

        // 调用仓储层删除菜单
        await _menuRepository.DeleteAsync(menu);
        // 返回删除成功标志
        return true;
    }

    // 根据角色ID获取菜单列表
    public async Task<IEnumerable<MenuDto>> GetMenusByRoleAsync(Guid roleId)
    {
        // 调用仓储层获取角色关联的菜单ID列表
        var menuIds = await _menuRoleRepository.GetMenuIdsByRoleAsync(roleId);
        // 调用仓储层根据菜单ID列表获取菜单列表
        var menus = await _menuRepository.GetByIdsAsync(menuIds);
        // 将菜单实体映射为DTO并返回
        return menus.Select(MapToDto);
    }

    // 为角色分配菜单
    public async Task AssignMenusToRoleAsync(Guid roleId, List<Guid> menuIds)
    {
        // 先删除现有分配
        await _menuRoleRepository.DeleteByRoleAsync(roleId);
        
        // 添加新的分配
        var menuRoles = menuIds.Select(menuId => new MenuRole
        {
            RoleId = roleId,
            MenuId = menuId
        });
        
        // 调用仓储层批量添加菜单角色关联
        await _menuRoleRepository.AddRangeAsync(menuRoles);
    }

    // 递归构建菜单树
    private void BuildMenuTree(MenuDto parent, List<MenuDto> allMenus)
    {
        // 设置当前菜单的子菜单列表
        parent.Children = allMenus
            .Where(m => m.ParentId == parent.Id)
            .OrderBy(m => m.SortOrder)
            .ToList();
        
        // 递归构建每个子菜单的子树
        foreach (var child in parent.Children)
        {
            BuildMenuTree(child, allMenus);
        }
    }

    // 将菜单实体映射为DTO
    private static MenuDto MapToDto(Menu menu)
    {
        return new MenuDto
        {
            Id = menu.Id,
            Name = menu.Name,
            Path = menu.Path,
            Icon = menu.Icon,
            ParentId = menu.ParentId,
            SortOrder = menu.SortOrder,
            CreatedAt = menu.CreatedAt,
            UpdatedAt = menu.UpdatedAt
        };
    }
} 